package com.tyut.musicdreamer.framework.starter.storage.service.impl;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import com.tyut.musicdreamer.framework.starter.storage.config.StorageProperties;
import com.tyut.musicdreamer.framework.starter.storage.model.StorageClass;
import com.tyut.musicdreamer.framework.starter.storage.model.UploadResult;
import com.tyut.musicdreamer.framework.starter.storage.service.StorageService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.UUID;

/**
 * 本地存储服务实现
 */
@Slf4j
@RequiredArgsConstructor
public class LocalStorageServiceImpl implements StorageService {

    private final StorageProperties properties;

    @Override
    public UploadResult store(MultipartFile file, String directory) throws IOException {
        // 验证文件
        validateFile(file);

        // 存储文件
        return storeFile(file.getInputStream(), file.getOriginalFilename(), file.getContentType(), file.getSize(), directory, StorageClass.STANDARD);
    }
    
    @Override
    public UploadResult store(MultipartFile file, String directory, StorageClass storageClass) throws IOException {
        // 验证文件
        validateFile(file);

        // 存储文件
        return storeFile(file.getInputStream(), file.getOriginalFilename(), file.getContentType(), file.getSize(), directory, storageClass);
    }

    @Override
    public UploadResult store(InputStream inputStream, String fileName, String contentType, long fileSize, String directory) throws IOException {
        return storeFile(inputStream, fileName, contentType, fileSize, directory, StorageClass.STANDARD);
    }
    
    @Override
    public UploadResult store(InputStream inputStream, String fileName, String contentType, long fileSize, String directory, StorageClass storageClass) throws IOException {
        return storeFile(inputStream, fileName, contentType, fileSize, directory, storageClass);
    }
    
    /**
     * 存储文件的内部实现
     */
    private UploadResult storeFile(InputStream inputStream, String fileName, String contentType, long fileSize, String directory, StorageClass storageClass) throws IOException {
        // 生成唯一文件名
        String originalFilename = StrUtil.isNotBlank(fileName) ? fileName : "unknown";
        String extension = FileUtil.extName(originalFilename);
        String objectKey = buildObjectKey(directory, extension);

        // 确保目录存在
        Path dirPath = Paths.get(properties.getLocal().getBasePath(), directory);
        Files.createDirectories(dirPath);

        // 存储文件
        Path filePath = Paths.get(properties.getLocal().getBasePath(), objectKey);
        Files.copy(inputStream, filePath, StandardCopyOption.REPLACE_EXISTING);
        
        // 记录存储类别（本地存储只是记录，不实际处理）
        log.info("文件已存储，路径：{}，存储类别：{}", filePath, storageClass);

        // 生成访问URL
        String fileUrl = getFileUrl(objectKey);

        // 构建上传结果
        return UploadResult.builder()
                .objectKey(objectKey)
                .fileName(originalFilename)
                .fileSize(fileSize)
                .contentType(contentType)
                .url(fileUrl)
                .cdnUrl(getCdnUrl(objectKey))
                .presignedUrl(fileUrl) // 本地存储不需要预签名
                .build();
    }

    @Override
    public String generatePresignedUrl(String objectKey, int expirationMinutes) {
        // 本地存储不需要预签名，直接返回访问URL
        return getFileUrl(objectKey);
    }

    @Override
    public UploadResult generatePresignedUploadUrl(String fileName, String contentType, String directory, int expirationMinutes) {
        return generatePresignedUploadUrl(fileName, contentType, directory, StorageClass.STANDARD, expirationMinutes);
    }
    
    @Override
    public UploadResult generatePresignedUploadUrl(String fileName, String contentType, String directory, StorageClass storageClass, int expirationMinutes) {
        // 本地存储不支持预签名上传，返回空结果
        String extension = FileUtil.extName(fileName);
        String objectKey = buildObjectKey(directory, extension);
        
        // 记录存储类别（本地存储只是记录，不实际处理）
        log.info("文件将使用存储类别：{}（本地存储不实际处理）", storageClass);
        
        return UploadResult.builder()
                .objectKey(objectKey)
                .fileName(fileName)
                .contentType(contentType)
                .url(getFileUrl(objectKey))
                .cdnUrl(getCdnUrl(objectKey))
                .build();
    }

    @Override
    public boolean delete(String objectKey) {
        if (StrUtil.isBlank(objectKey)) {
            return false;
        }

        try {
            Path filePath = Paths.get(properties.getLocal().getBasePath(), objectKey);
            return Files.deleteIfExists(filePath);
        } catch (Exception e) {
            log.error("删除文件失败: {}", objectKey, e);
            return false;
        }
    }

    @Override
    public InputStream getFileInputStream(String objectKey) throws IOException {
        if (StrUtil.isBlank(objectKey)) {
            log.warn("对象键为空");
            return null;
        }

        Path filePath = Paths.get(properties.getLocal().getBasePath(), objectKey);
        if (!Files.exists(filePath)) {
            log.warn("文件不存在: {}", filePath);
            return null;
        }

        return Files.newInputStream(filePath);
    }

    @Override
    public String getFileUrl(String objectKey) {
        if (StrUtil.isBlank(objectKey)) {
            return null;
        }

        // 拼接URL
        String urlPrefix = properties.getLocal().getUrlPrefix();
        if (StrUtil.isBlank(urlPrefix)) {
            return objectKey;
        }

        // 确保URL前缀以/结尾
        if (!urlPrefix.endsWith("/")) {
            urlPrefix = urlPrefix + "/";
        }

        // 确保对象键不以/开头
        String key = objectKey;
        if (key.startsWith("/")) {
            key = key.substring(1);
        }

        return urlPrefix + key;
    }
    
    @Override
    public String getCdnUrl(String objectKey) {
        // 本地存储不支持CDN，返回普通URL
        return getFileUrl(objectKey);
    }
    
    @Override
    public boolean updateStorageClass(String objectKey, StorageClass storageClass) {
        // 本地存储不支持存储类别切换，只记录日志
        log.info("本地存储不支持切换存储类别，忽略请求：objectKey={}, storageClass={}", objectKey, storageClass);
        return true;
    }

    /**
     * 验证文件
     */
    private void validateFile(MultipartFile file) {
        // 验证文件是否为空
        if (file == null || file.isEmpty()) {
            throw new IllegalArgumentException("文件不能为空");
        }

        // 验证文件类型
        String contentType = file.getContentType();
        if (contentType == null || (properties.getAllowedTypes() != null && !properties.getAllowedTypes().contains(contentType))) {
            throw new IllegalArgumentException("不支持的文件类型: " + contentType);
        }

        // 验证文件大小
        if (properties.getMaxSize() != null && file.getSize() > properties.getMaxSize()) {
            throw new IllegalArgumentException("文件大小超过限制: " + file.getSize() + " > " + properties.getMaxSize());
        }
    }

    /**
     * 构建对象键
     */
    private String buildObjectKey(String directory, String extension) {
        // 确保目录以/结尾
        String dir = StrUtil.isNotBlank(directory) ? directory : "";
        if (StrUtil.isNotBlank(dir) && !dir.endsWith("/")) {
            dir = dir + "/";
        }

        // 生成UUID作为文件名
        String uuid = UUID.randomUUID().toString();
        
        // 构建对象键
        return dir + uuid + (StrUtil.isNotBlank(extension) ? "." + extension : "");
    }
} 